Isaac ROS Common 3.2.0: 커스텀 Dockerfile 아키텍처 및 build_image_layers.sh 활용 방법론

Isaac ROS Common 3.2.0: 커스텀 Dockerfile 아키텍처 및 build_image_layers.sh 활용 방법론

2025-12-17, G30DR

1. 서론: 로봇 소프트웨어 개발 환경의 가상화와 표준화의 필요성

현대 로보틱스 소프트웨어 엔지니어링, 특히 자율 주행 로봇(AMR)과 매니퓰레이터의 지능형 제어 시스템 개발은 전례 없는 복잡성에 직면해 있다. 과거의 임베디드 소프트웨어 개발이 단일 마이크로컨트롤러(MCU) 위에서의 펌웨어 작성에 국한되었다면, 현재의 로봇 시스템은 고성능 엣지 컴퓨팅 장치(예: NVIDIA Jetson Orin) 위에서 복잡한 미들웨어(ROS 2), 딥러닝 추론 엔진(TensorRT, Triton), 그리고 컴퓨터 비전 라이브러리(OpenCV, VPI)가 유기적으로 결합된 형태를 띤다. 이러한 환경에서 가장 치명적인 병목 현상 중 하나는 ’개발 환경의 파편화’와 ’의존성 지옥(Dependency Hell)’이다.

NVIDIA Isaac ROS는 하드웨어 가속을 통해 로봇 애플리케이션의 성능을 극대화하는 SDK 모음이다. 그러나 이를 효과적으로 활용하기 위해서는 호스트 운영체제, CUDA 툴킷 버전, cuDNN 라이브러리, 그리고 ROS 2 배포판(Humble 등) 간의 정밀한 버전 일치가 필수적이다. 로컬 호스트에 직접 라이브러리를 설치하는 방식은 시스템의 오염을 초래하고, 팀 단위의 협업 시 “내 컴퓨터에서는 되는데 너의 컴퓨터에서는 안 되는” 상황을 빈번하게 발생시킨다. 이러한 배경에서 컨테이너 가상화 기술, 즉 Docker의 도입은 선택이 아닌 필수가 되었다.

isaac_ros_common 패키지는 NVIDIA가 제안하는 표준화된 Docker 개발 환경의 청사진이다. 이는 단순한 Dockerfile의 모음이 아니라, 호스트의 하드웨어 리소스(GPU, 입력 장치, 네트워크 등)를 컨테이너 내부로 투명하게 전달하고, 복잡한 의존성 계층을 모듈화하여 관리할 수 있도록 돕는 정교한 스크립트 시스템이다. 본 보고서는 isaac_ros_common 3.2.0 버전을 기준으로, 개발자가 자신의 프로젝트 요구사항에 부합하는 커스텀 환경을 구축하기 위해 필수적인 아키텍처 이해, build_image_layers.sh 스크립트의 동작 원리, 그리고 실제 커스텀 Dockerfile 작성 및 트러블슈팅 전략을 심도 있게 분석한다.

2. Isaac ROS Common 3.2.0 아키텍처 및 레이어 시스템

2.1 모놀리식 구조의 한계와 레이어드 아키텍처의 도입

전통적인 Docker 이미지 빌드 방식은 하나의 거대한 Dockerfile(Dockerfile)에 베이스 OS부터 최종 애플리케이션 코드까지 모든 설치 과정을 기술하는 ‘모놀리식(Monolithic)’ 접근법을 취하는 경우가 많았다. 이 방식은 구조가 단순하다는 장점이 있지만, 로보틱스 개발 환경, 특히 딥러닝 모델과 무거운 미들웨어가 포함된 환경에서는 심각한 비효율을 초래한다. 예를 들어, 최상위 레이어의 애플리케이션 코드 한 줄을 수정하기 위해 하위의 CUDA 라이브러리나 ROS 2 패키지 전체를 다시 빌드해야 하는 상황이 발생할 수 있다. 또한, 팀 내에서 서로 다른 프로젝트가 공통의 베이스 환경을 공유하기 어렵게 만든다.

isaac_ros_common은 이러한 문제를 해결하기 위해 이미지 키(Image Key) 기반의 동적 레이어드 아키텍처를 채택하였다. 이 시스템은 이미지를 레고 블록처럼 쌓아 올리는 개념으로 설계되었다. 각 블록은 개별적인 Dockerfile로 정의되며, build_image_layers.sh 스크립트가 사용자가 지정한 순서에 따라 이들을 결합하여 최종 이미지를 생성한다.

2.2 이미지 키(Image Key) 파싱 및 빌드 시퀀스

이미지 키 시스템은 점(.)으로 구분된 문자열을 통해 빌드 순서를 정의한다. 이는 그래프 이론에서의 경로 탐색과 유사하게 작동한다. 예를 들어, 사용자가 ros2_humble.mine이라는 이미지 키를 지정했다고 가정하자. 시스템은 이를 다음과 같은 논리적 시퀀스로 해석한다.

  1. 토큰 분리(Tokenization): 입력된 문자열 ros2_humble.mineros2_humblemine이라는 두 개의 토큰으로 분리된다.
  2. 리소스 탐색(Resource Discovery): 스크립트는 사전에 정의된 검색 경로(CONFIG_DOCKER_SEARCH_DIRS)를 순회하며 각 토큰에 해당하는 Dockerfile을 찾는다.
  • ros2_humble -> Dockerfile.ros2_humble
  • mine -> Dockerfile.mine
  1. 체인 빌드(Chain Build):
  • Step 1: 먼저 Dockerfile.ros2_humble을 빌드한다. 이때 베이스 이미지는 플랫폼(x86_64 또는 aarch64)에 따라 자동으로 결정된 기본 OS 이미지(예: Ubuntu 22.04)가 된다.
  • Step 2: Step 1에서 생성된 이미지의 고유 ID(SHA256 해시)가 추출된다.
  • Step 3: 추출된 이미지 ID는 ARG BASE_IMAGE라는 빌드 인자를 통해 Dockerfile.mine에 주입된다. 즉, Dockerfile.mineFROM ${BASE_IMAGE} 구문을 통해 앞 단계의 결과물을 자신의 기반으로 삼는다.

이러한 메커니즘을 통해 NVIDIA는 ros2_humble과 같은 공통 베이스 이미지를 미리 빌드하여 NVCR(NVIDIA Container Registry)에 배포하고, 개발자는 그 위에 자신만의 얇은 레이어(mine)만 추가함으로써 빌드 시간을 획기적으로 단축할 수 있다.

2.3 버전 3.2.0의 주요 변경점과 Dockerfile 리팩토링

isaac_ros_common 3.2.0 버전은 이전 버전 대비 몇 가지 중요한 변화가 있었다. 특히 Dockerfile의 구조가 리팩토링되어 유지보수성이 향상되었으며, JetPack 6.x 지원을 위한 NVIDIA Container Toolkit(NCT) 호환성 업데이트가 포함되었다. 또한, 과거에는 하나의 Dockerfile 내에서 아키텍처별 분기를 처리하는 경우가 많았으나, 3.2.0에서는 Dockerfile.aarch64Dockerfile.x86_64와 같이 플랫폼별로 명확히 분리된 파일 구조를 지향하거나, 빌드 스크립트 레벨에서 아키텍처를 감지하여 적절한 파일을 매칭하는 로직이 강화되었다. 이는 크로스 컴파일의 복잡성을 줄이고 네이티브 빌드의 안정성을 높이기 위함이다.

3. 하드웨어 및 호스트 환경 구성

성공적인 Docker 빌드와 실행을 위해서는 호스트 시스템의 준비가 선행되어야 한다. 특히 Jetson 플랫폼은 임베디드 장비의 특성상 리소스 제약이 따르므로 세심한 설정이 요구된다.

3.1 스토리지 최적화: NVMe SSD 필수 사용

Jetson 개발자 키트(예: Orin Nano, AGX Orin)는 기본적으로 SD 카드나 eMMC를 부트 드라이브로 사용한다. 그러나 Docker 빌드 프로세스, 특히 ROS 2와 같이 거대한 미들웨어를 컴파일하거나 대용량 레이어를 처리하는 과정에서는 막대한 디스크 I/O가 발생한다. 플래시 메모리 기반의 기본 스토리지는 쓰기 속도와 IOPS(Input/Output Operations Per Second) 한계로 인해 빌드 시간을 기하급수적으로 늘리거나, 심지어 프리징 현상을 유발할 수 있다.

따라서 NVMe SSD를 장착하고 Docker의 데이터 루트 디렉토리(/var/lib/docker)를 SSD로 마이그레이션하는 것이 강력히 권장된다. 구체적인 절차는 다음과 같이 분석된다.

  1. 서비스 중단: 데이터 이동 중 무결성을 위해 Docker 데몬을 중지한다.

    sudo systemctl stop docker
    

2. **데이터 이관:** 단순 복사(`cp`)보다는 권한과 심볼릭 링크를 보존하는 `rsync`를 사용해야 한다.

   ```Bash
   sudo rsync -axPS /var/lib/docker/ /mnt/nova_ssd/docker/

여기서 -a는 아카이브 모드, -x는 파일 시스템 경계 준수, -P는 진행 상황 표시 및 부분 전송 재개를 의미한다.

  1. 설정 변경: /etc/docker/daemon.json을 수정하여 data-root를 변경하거나, 기존 경로를 바인드 마운트하는 방식을 사용한다. 이후 데몬을 재시작한다.

    sudo systemctl daemon-reload && sudo systemctl restart docker
    

### 3.2  권한 관리 및 필수 유틸리티


Docker 명령어를 실행할 때마다 `sudo`를 입력하는 것은 개발 효율을 떨어뜨릴 뿐만 아니라, 생성된 파일의 소유권 문제를 야기할 수 있다. 사용자를 `docker` 그룹에 추가하여 비-루트(non-root) 권한으로 컨테이너를 제어할 수 있도록 설정해야 한다.

```Bash
sudo usermod -aG docker $USER
newgrp docker

또한, isaac_ros_common은 대용량 바이너리 파일이나 사전 학습된 모델을 관리하기 위해 Git LFS(Large File Storage)를 적극적으로 사용한다. LFS가 설치되지 않은 상태에서 리포지토리를 클론하면 실제 데이터 대신 포인터 파일만 다운로드되어, 빌드 시점에 “파일을 찾을 수 없음” 또는 “포맷 오류“가 발생하게 된다. 따라서 반드시 git-lfs 패키지를 설치하고 초기화해야 한다.

sudo apt-get install git-lfs
git lfs install --skip-repo

3.3 리포지토리 클론 및 환경 변수 설정

작업 공간 구성은 표준화된 경로를 따르는 것이 isaac_ros_common의 스크립트들이 기본값으로 동작하는 데 유리하다. 일반적으로 ~/workspaces/isaac_ros-dev/src 하위에 패키지를 위치시킨다.

설정 항목권장 값 및 명령어설명
Workspace Root~/workspaces/isaac_ros-dev모든 Isaac ROS 프로젝트의 최상위 디렉토리
ISAAC_ROS_WSexport ISAAC_ROS_WS=~/workspaces/isaac_ros-dev스크립트 내부에서 참조하는 핵심 환경 변수
Clonegit clone -b release-3.2...3.2.0 버전을 명시적으로 체크아웃해야 함

.bashrc 파일에 export ISAAC_ROS_WS=...를 추가하여 터미널을 열 때마다 자동으로 변수가 로드되도록 하는 것이 실수를 줄이는 방법이다.

4. build_image_layers.sh 심층 분석 및 사용법

build_image_layers.sh 스크립트는 Isaac ROS Docker 환경 구축의 중추적인 역할을 담당하는 실행 파일이다. 이 스크립트는 isaac_ros_common/scripts 디렉토리에 위치하며, 사용자가 직접 호출하거나 run_dev.sh에 의해 내부적으로 호출된다.

4.1 스크립트 실행 로직 및 인수(Argument) 분석

이 스크립트의 실행 과정은 단순한 docker build 래퍼(wrapper) 이상이다. 스크립트는 다음과 같은 단계로 실행된다.

  1. 인수 파싱(Argument Parsing): 스크립트는 사용자가 전달한 플래그를 분석한다. 주요 인수는 다음과 같다.
  • -i 또는 --image_key: 빌드할 대상 이미지 키 (예: ros2_humble.mine). 필수 인수이다.
  • -b 또는 --base_image: 최상위 베이스 이미지를 강제로 지정한다. 지정하지 않을 경우 플랫폼별 기본값(Ubuntu Base)이 사용된다.
  • --skip_image_build: Docker 빌드 과정을 생략한다. 이는 오프라인 환경이거나 이미 이미지가 존재함을 확신할 때 사용한다.
  • -a 또는 --arch: 대상 아키텍처(x86_64 또는 aarch64)를 지정한다.
  1. 레이어 매칭 및 정렬: 입력된 이미지 키를 분해하고, CONFIG_DOCKER_SEARCH_DIRS에 정의된 경로들에서 해당하는 Dockerfile을 찾는다. 이때 가장 긴 부분 수열(longest subsequence) 매칭 알고리즘을 사용하여, first.second.third와 같은 키가 입력되었을 때 가능한 Dockerfile 조합을 찾아낸다.

  2. 캐시 확인 및 원격 레지스트리 조회: 각 레이어에 대해 Dockerfile의 내용과 관련 파일(context)의 해시(checksum)를 계산한다. 이 해시값을 태그로 하는 이미지가 NVIDIA의 레지스트리(NVCR)나 로컬 캐시에 존재하는지 확인한다. 만약 존재한다면, 빌드 과정을 건너뛰고 해당 이미지를 다운로드(pull)한다. 이는 빌드 시간을 획기적으로 단축시키는 핵심 기능이다.

  3. 순차적 빌드 및 인자 주입:

캐시가 없는 레이어에 대해서는 docker build 명령을 실행한다. 이때 가장 중요한 점은, 직전 단계에서 생성(또는 다운로드)된 이미지의 ID를 BASE_IMAGE라는 빌드 인자(Build Argument)로 주입한다는 것이다.

4.2 명령행 실행 예시

개발자가 isaac_ros_common/scripts 디렉토리로 이동하여 직접 스크립트를 실행하는 경우의 예시는 다음과 같다.

cd ${ISAAC_ROS_WS}/src/isaac_ros_common/scripts

# 기본 Humble 환경 위에 커스텀 'mine' 레이어를 얹어 빌드
./build_image_layers.sh --image_key "ros2_humble.mine"

만약 특정 베이스 이미지를 명시해야 한다면 -b 옵션을 사용할 수 있으나, 일반적으로는 스크립트가 Dockerfile.x86_64 또는 Dockerfile.aarch64를 통해 자동으로 베이스를 결정하도록 두는 것이 안전하다.

4.3 오프라인 빌드 모드 활용

현장의 보안 정책이나 네트워크 제약으로 인해 인터넷 연결이 불가능한 경우, --skip_image_build 옵션을 사용하여 build_image_layers.sh가 외부 레지스트리에 접속하려는 시도를 차단할 수 있다. 단, 이 경우 로컬 Docker 데몬에 필요한 모든 이미지 레이어가 사전에 빌드되어 있어야 한다.

5. 커스텀 Dockerfile 작성 방법론

build_image_layers.sh 시스템과 호환되는 Dockerfile을 작성하기 위해서는 일반적인 Dockerfile 작성법과는 다른, Isaac ROS만의 규칙을 준수해야 한다.

5.1 ARG BASE_IMAGE 필수 선언 규칙

이것은 가장 빈번하게 발생하는 오류의 원인이다. Isaac ROS의 레이어드 빌드 시스템에서 모든 하위 레이어(첫 번째 베이스 레이어 제외)는 동적으로 주입되는 베이스 이미지를 받아야 한다. 따라서 Dockerfile의 최상단에는 반드시 ARG BASE_IMAGE가 선언되어야 하며, FROM 지시어는 이를 참조해야 한다.

잘못된 예시:

# 정적 이미지를 사용하면 레이어 체인이 끊김
FROM ubuntu:22.04 
...

올바른 예시 (Dockerfile.mine):

# 빌드 스크립트로부터 베이스 이미지를 전달받음
ARG BASE_IMAGE
FROM ${BASE_IMAGE}

# 이후 커스텀 설정 진행
RUN apt-get update &&...

만약 ARG BASE_IMAGE를 선언하지 않으면, 빌드 스크립트가 --build-arg BASE_IMAGE=...를 전달할 때 Docker 엔진이 이를 받아들일 변수가 없어 경고를 발생시키거나, FROM 절에서 빈 변수를 참조하여 빌드가 실패하게 된다.

5.2 파일 명명 및 위치 전략

Dockerfile의 이름은 이미지 키의 세그먼트와 정확히 일치해야 한다. 예를 들어 ros2_humble.mine이라는 키를 사용하려면 파일명은 반드시 Dockerfile.mine이어야 한다. 파일의 위치는 기본적으로 isaac_ros_common/docker 디렉토리이지만, 소스 코드 관리의 편의를 위해 사용자 별도의 디렉토리에 저장하고, 후술할 설정 파일을 통해 경로를 지정하는 것이 권장된다.

5.3 효율적인 레이어 구성 및 캐싱 활용

Dockerfile 내의 명령어 순서는 빌드 속도에 지대한 영향을 미친다. 변경 빈도가 낮은 명령어(예: 시스템 패키지 설치)를 상단에, 변경 빈도가 높은 명령어(예: 소스 코드 복사, pip 패키지 설치)를 하단에 배치해야 Docker의 레이어 캐싱 기능을 극대화할 수 있다.

또한, apt-get updateapt-get install은 반드시 동일한 RUN 명령줄 내에서 &&로 연결하여 실행해야 한다. 이는 오래된 패키지 목록 캐시로 인해 설치가 실패하는 것을 방지하기 위함이다. 설치 후에는 /var/lib/apt/lists/*를 삭제하여 이미지 크기를 줄이는 것이 표준 관례이다.

작성 예시:

RUN apt-get update && apt-get install -y --no-install-recommends \
    python3-pip \
    vim \
    git \
    && rm -rf /var/lib/apt/lists/*

5.4 Python 패키지 의존성 관리

Isaac ROS 환경에서는 시스템 Python과의 충돌을 피하기 위해 python3 -m pip 형식을 사용하는 것이 좋다. 최근 보고된 이슈에 따르면, mapbox_earcut 등 일부 패키지는 빌드 도구(ninja-build, cmake)가 사전에 설치되어 있지 않으면 pip install 과정에서 휠(wheel) 빌드에 실패하여 전체 Docker 빌드를 중단시킬 수 있다.

따라서 복잡한 Python 패키지를 설치할 때는 다음과 같이 빌드 의존성을 먼저 해결하는 전략이 필요하다.

# 빌드 도구 선행 설치
RUN apt-get update && apt-get install -y ninja-build

# 의존성 문제 발생 시 개별 설치로 분리
RUN python3 -m pip install -U pip
RUN python3 -m pip install -U mapbox_earcut
RUN python3 -m pip install -U -r requirements.txt

6. .isaac_ros_common-config를 통한 환경 개인화

매번 run_dev.sh 실행 시 긴 인수를 입력하는 것은 비효율적이다. isaac_ros_common은 홈 디렉토리에 위치한 .isaac_ros_common-config 파일을 통해 사용자별 설정을 로드하는 기능을 제공한다.

6.1 설정 파일 생성 및 구조

홈 디렉토리에 .isaac_ros_common-config 파일을 생성하고 쉘 스크립트 문법으로 변수를 정의한다. 이 파일은 run_dev.sh 실행 시 자동으로 소싱(sourcing)된다.

구성 예시:

# ~/.isaac_ros_common-config

# 1. 커스텀 이미지 키 지정
# 기본 ros2_humble 위에 my_custom 레이어를 추가
CONFIG_IMAGE_KEY="ros2_humble.my_custom"

# 2. Dockerfile 검색 경로 확장
# 사용자의 커스텀 Dockerfile이 위치한 경로를 배열의 첫 번째 요소로 추가
CONFIG_DOCKER_SEARCH_DIRS=(
    "/home/user/workspaces/isaac_ros-dev/ros_ws/docker_context"
    "/home/user/workspaces/isaac_ros-dev/src/isaac_ros_common/docker"
)

# 3. 컨테이너 이름 식별자
CONFIG_CONTAINER_NAME_SUFFIX="dev_env_v1"

6.2 CONFIG_DOCKER_SEARCH_DIRS의 중요성

build_image_layers.sh는 이 배열 변수에 나열된 디렉토리를 순서대로 검색한다. 만약 사용자가 기본 제공되는 Dockerfile.ros2_humble을 수정하여 덮어쓰고 싶다면, 수정된 파일이 있는 디렉토리를 배열의 앞부분에 배치함으로써 기본 파일보다 우선순위를 갖게 할 수 있다. 이를 통해 원본 소스 코드를 건드리지 않고도 유연하게 환경을 오버라이딩(Overriding)할 수 있다.

7. 실제 빌드 시나리오 분석 및 트러블슈팅

7.1 시나리오: ZED 카메라 연동 환경 구축

로봇 개발에서 ZED 스테레오 카메라를 사용하는 경우, ZED SDK와 관련 드라이버를 Docker 컨테이너 내부에 설치해야 한다. 이를 isaac_ros_common 체계 안에서 구현하는 절차는 다음과 같다.

  1. Dockerfile 작성: Dockerfile.zed를 생성하고 ZED SDK 설치 스크립트를 RUN 명령어로 실행한다.

    ARG BASE_IMAGE
    FROM ${BASE_IMAGE}
    COPY install-zed-aarch64.sh /usr/local/bin/
    RUN chmod +x /usr/local/bin/install-zed-aarch64.sh && \
        /usr/local/bin/install-zed-aarch64.sh silent
    

2. **설정 변경:** `.isaac_ros_common-config`에서 `CONFIG_IMAGE_KEY="ros2_humble.zed"`로 설정한다.

3. **빌드 및 실행:** `run_dev.sh`를 실행하면 `ros2_humble` 이미지를 베이스로 하여 `zed` 레이어가 추가된 최종 이미지가 빌드되고 컨테이너가 실행된다.

### 7.2  주요 오류 사례 및 해결 방안


**Case 1: CDI (Container Device Interface) 장치 주입 실패** JetPack 6.1 기반의 최신 Jetson 환경에서 `run_dev.sh` 실행 시 "failed to inject CDI devices" 오류가 발생하는 사례가 다수 보고되었다. 이는 NVIDIA Container Toolkit이 GPU 및 가속기(PVA, VIC 등)를 컨테이너에 노출시키는 방식(CDI)의 설정 파일이 손상되었거나 호환되지 않을 때 발생한다.

- **해결:** `nvidia-ctk` 도구를 사용하여 CDI 사양을 CSV 모드로 재생성해야 한다.

  ```Bash
  sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml --mode=csv
  sudo systemctl restart docker

이후에도 문제가 지속되면 run_dev.sh 내에서 NVIDIA_VISIBLE_DEVICES 환경 변수 설정을 수동으로 주입하는 우회 방법을 고려해야 한다.

Case 2: UndefinedVar: Usage of undefined variable '$CMAKE_PREFIX_PATH' Docker 빌드 중 CMake 경로 관련 변수가 정의되지 않았다는 경고와 함께 빌드가 멈추는 경우가 있다. 이는 쉘 확장(Shell Expansion)과 Docker 변수 처리 간의 충돌일 수 있다.

  • 해결: Dockerfile 내에서 환경 변수를 선언할 때 기본값을 제공하는 문법을 사용한다.

    ENV CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH:-/usr/local}:/my/custom/path
    

**Case 3: Python `pip` 프로세스 강제 종료 (Killed)** Jetson Orin Nano(8GB)와 같이 메모리가 제한된 장치에서 무거운 Python 라이브러리(예: `torch`, `tensorflow`)를 컴파일하여 설치할 때 메모리 부족(OOM)으로 프로세스가 사멸될 수 있다.

- **해결:** 스왑(Swap) 메모리를 8GB 이상 추가로 할당하거나, `pip install` 명령을 여러 줄로 나누어 한 번에 하나의 패키지만 처리하도록 Dockerfile을 수정한다. 또한 `--no-cache-dir` 옵션을 사용하여 pip 캐시가 메모리를 점유하지 않도록 한다.

## 8.  `docker_deploy.sh`를 활용한 배포 이미지 생성


개발 단계가 완료되어 로봇에 소프트웨어를 배포할 시점이 되면, 개발 도구(컴파일러, 디버거 등)가 제거되고 실행에 필요한 런타임 요소만 포함된 경량화된 이미지가 필요하다. `docker_deploy.sh` 스크립트는 이러한 배포용 이미지를 생성하는 역할을 한다.

### 8.1  배포 스크립트의 기능


이 스크립트는 내부적으로 `build_image_layers.sh`를 사용하여 베이스 환경을 구축한 뒤, 사용자가 빌드한 ROS 2 워크스페이스의 산출물(`install` 디렉토리)과 지정된 `.deb` 패키지들을 이미지 위에 복사(Copy)하거나 설치한다.

### 8.2  사용 예시


다음 명령어는 `ros2_humble` 베이스 위에 현재 워크스페이스의 빌드 결과물을 얹어 `my_robot_app:v1`이라는 이름의 배포 이미지를 생성한다.

```Bash
cd ${ISAAC_ROS_WS}/src/isaac_ros_common/scripts
./docker_deploy.sh \
    --base_image_key "aarch64.ros2_humble" \
    --output_image_name "my_robot_app:v1" \
    --workspace_dir "${ISAAC_ROS_WS}/install" \
    --install_debians "ros-humble-isaac-ros-apriltag"

생성된 이미지는 docker save를 통해 타르볼(tarball)로 저장하거나, docker push를 통해 원격 레지스트리로 전송하여 로봇 플릿(Fleet) 전체에 배포할 수 있다.

9. 결론 및 향후 전망

isaac_ros_common 3.2.0은 복잡한 로봇 소프트웨어의 의존성 문제를 해결하기 위해 고도화된 레이어드 빌드 시스템을 제공한다. build_image_layers.sh를 중심으로 한 이 아키텍처는 개발자에게 유연성(커스텀 Dockerfile)과 효율성(캐싱 및 프리빌드 이미지)을 동시에 제공한다. 특히 Jetson 플랫폼에서의 하드웨어 가속 기능을 컨테이너 내부로 온전히 가져오기 위해서는 본 보고서에서 다룬 ARG BASE_IMAGE 패턴의 준수, 올바른 스토리지 설정(NVMe SSD), 그리고 CDI 관련 트러블슈팅 능력이 필수적이다.

향후 Isaac ROS 4.0 및 ROS 2 Jazzy로의 전환 과정에서도 이러한 컨테이너 기반의 개발 방법론은 더욱 강화될 것이며, isaac_ros_common의 활용 능력은 로봇 엔지니어의 핵심 역량이 될 것이다. 개발자는 단순한 사용법 숙지를 넘어, 스크립트 내부의 동작 원리를 이해함으로써 예기치 않은 빌드 오류에 능동적으로 대처할 수 있어야 한다.

10. 참고 자료

  1. Isaac ROS Dev — isaac_ros_docs documentation, https://nvidia-isaac-ros.github.io/v/release-3.1/concepts/docker_devenv/index.html
  2. Default value for ARG ${BASE_IMAGE} results in empty or invalid …, https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_common/issues/155
  3. Isaac ROS Common, https://nvidia-isaac-ros.github.io/repositories_and_packages/isaac_ros_common/index.html
  4. NVIDIA-ISAAC-ROS/isaac_ros_common - run_dev.sh failing - GitHub, https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_common/issues/163
  5. Installing Isaac ROS on Jetson - AVerMedia Developer, https://developer.avermedia.com/blog/isaac-ros-on-jetson/
  6. Setting up Isaac™ ROS to work with ZED Cameras in ROS 2, https://www.stereolabs.com/docs/isaac-ros/setting_up_isaac_ros
  7. How to create a Docker Image of Issac-ROS with Dockerfile, https://forums.developer.nvidia.com/t/how-to-create-a-docker-image-of-issac-ros-with-dockerfile/306427
  8. build_image_layers.sh Error on common 9/18 · Issue #168 - GitHub, https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_common/issues/168
  9. Installing ZED SDK 5.0 into docker image - Stereolabs Forums, https://community.stereolabs.com/t/installing-zed-sdk-5-0-into-docker-image/9294